1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package com.sun.java.util.jar.pack;
27
28 import com.sun.java.util.jar.pack.ConstantPool.ClassEntry;
29 import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry;
30 import com.sun.java.util.jar.pack.ConstantPool.Entry;
31 import com.sun.java.util.jar.pack.ConstantPool.Index;
32 import com.sun.java.util.jar.pack.ConstantPool.IndexGroup;
33 import com.sun.java.util.jar.pack.ConstantPool.MemberEntry;
34 import com.sun.java.util.jar.pack.ConstantPool.NumberEntry;
35 import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry;
36 import com.sun.java.util.jar.pack.ConstantPool.StringEntry;
37 import com.sun.java.util.jar.pack.Package.Class;
38 import com.sun.java.util.jar.pack.Package.File;
39 import com.sun.java.util.jar.pack.Package.InnerClass;
40 import java.io.IOException;
41 import java.io.OutputStream;
42 import java.io.PrintStream;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Comparator;
46 import java.util.HashMap;
47 import java.util.HashSet;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Set;
51 import static com.sun.java.util.jar.pack.Constants.*;
52
53
54
55
56
57 class PackageWriter extends BandStructure {
58 Package pkg;
59 OutputStream finalOut;
60
61 PackageWriter(Package pkg, OutputStream out) throws IOException {
62 this.pkg = pkg;
63 this.finalOut = out;
64
65 initPackageMajver(pkg.package_majver);
66 }
67
68 void write() throws IOException {
69 boolean ok = false;
70 try {
71 if (verbose > 0) {
72 Utils.log.info("Setting up constant pool...");
73 }
74 setup();
75
76 if (verbose > 0) {
77 Utils.log.info("Packing...");
78 }
79
80
81
82 writeConstantPool();
83 writeFiles();
84 writeAttrDefs();
85 writeInnerClasses();
86 writeClassesAndByteCodes();
87 writeAttrCounts();
88
89 if (verbose > 1) printCodeHist();
90
91
92 if (verbose > 0) {
93 Utils.log.info("Coding...");
94 }
95 all_bands.chooseBandCodings();
96
97
98 writeFileHeader();
99
100 writeAllBandsTo(finalOut);
101
102 ok = true;
103 } catch (Exception ee) {
104 Utils.log.warning("Error on output: "+ee, ee);
105
106
107 if (verbose > 0) finalOut.close();
108 if (ee instanceof IOException) throw (IOException)ee;
109 if (ee instanceof RuntimeException) throw (RuntimeException)ee;
110 throw new Error("error packing", ee);
111 }
112 }
113
114 Set<Entry> requiredEntries;
115 Map<Attribute.Layout, int[]> backCountTable;
116 int[][] attrCounts;
117
118 void setup() {
119 requiredEntries = new HashSet<>();
120 setArchiveOptions();
121 trimClassAttributes();
122 collectAttributeLayouts();
123 pkg.buildGlobalConstantPool(requiredEntries);
124 setBandIndexes();
125 makeNewAttributeBands();
126 collectInnerClasses();
127 }
128
129 void setArchiveOptions() {
130
131
132
133
134 int minModtime = pkg.default_modtime;
135 int maxModtime = pkg.default_modtime;
136 int minOptions = -1;
137 int maxOptions = 0;
138
139
140 archiveOptions |= pkg.default_options;
141
142 for (File file : pkg.files) {
143 int modtime = file.modtime;
144 int options = file.options;
145
146 if (minModtime == NO_MODTIME) {
147 minModtime = maxModtime = modtime;
148 } else {
149 if (minModtime > modtime) minModtime = modtime;
150 if (maxModtime < modtime) maxModtime = modtime;
151 }
152 minOptions &= options;
153 maxOptions |= options;
154 }
155 if (pkg.default_modtime == NO_MODTIME) {
156
157 pkg.default_modtime = minModtime;
158 }
159 if (minModtime != NO_MODTIME && minModtime != maxModtime) {
160
161 archiveOptions |= AO_HAVE_FILE_MODTIME;
162 }
163
164 if (!testBit(archiveOptions,AO_DEFLATE_HINT) && minOptions != -1) {
165 if (testBit(minOptions, FO_DEFLATE_HINT)) {
166
167
168 archiveOptions |= AO_DEFLATE_HINT;
169 minOptions -= FO_DEFLATE_HINT;
170 maxOptions -= FO_DEFLATE_HINT;
171 }
172 pkg.default_options |= minOptions;
173 if (minOptions != maxOptions
174 || minOptions != pkg.default_options) {
175 archiveOptions |= AO_HAVE_FILE_OPTIONS;
176 }
177 }
178
179 Map<Integer, int[]> verCounts = new HashMap<>();
180 int bestCount = 0;
181 int bestVersion = -1;
182 for (Class cls : pkg.classes) {
183 int version = cls.getVersion();
184 int[] var = verCounts.get(version);
185 if (var == null) {
186 var = new int[1];
187 verCounts.put(version, var);
188 }
189 int count = (var[0] += 1);
190
191 if (bestCount < count) {
192 bestCount = count;
193 bestVersion = version;
194 }
195 }
196 verCounts.clear();
197 if (bestVersion == -1) bestVersion = 0;
198 int bestMajver = (char)(bestVersion >>> 16);
199 int bestMinver = (char)(bestVersion);
200 pkg.default_class_majver = (short) bestMajver;
201 pkg.default_class_minver = (short) bestMinver;
202 String bestVerStr = Package.versionStringOf(bestMajver, bestMinver);
203 if (verbose > 0)
204 Utils.log.info("Consensus version number in segment is "+bestVerStr);
205 if (verbose > 0)
206 Utils.log.info("Highest version number in segment is "+
207 Package.versionStringOf(pkg.getHighestClassVersion()));
208
209
210 for (Class cls : pkg.classes) {
211 if (cls.getVersion() != bestVersion) {
212 Attribute a = makeClassFileVersionAttr(cls.minver, cls.majver);
213 if (verbose > 1) {
214 String clsVer = cls.getVersionString();
215 String pkgVer = bestVerStr;
216 Utils.log.fine("Version "+clsVer+" of "+cls
217 +" doesn't match package version "
218 +pkgVer);
219 }
220
221 cls.addAttribute(a);
222 }
223 }
224
225
226 for (File file : pkg.files) {
227 long len = file.getFileLength();
228 if (len != (int)len) {
229 archiveOptions |= AO_HAVE_FILE_SIZE_HI;
230 if (verbose > 0)
231 Utils.log.info("Note: Huge resource file "+file.getFileName()+" forces 64-bit sizing");
232 break;
233 }
234 }
235
236
237
238
239 int cost0 = 0;
240 int cost1 = 0;
241 for (Class cls : pkg.classes) {
242 for (Class.Method m : cls.getMethods()) {
243 if (m.code != null) {
244 if (m.code.attributeSize() == 0) {
245
246 cost1 += 1;
247 } else if (shortCodeHeader(m.code) != LONG_CODE_HEADER) {
248
249 cost0 += 3;
250 }
251 }
252 }
253 }
254 if (cost0 > cost1) {
255 archiveOptions |= AO_HAVE_ALL_CODE_FLAGS;
256 }
257 if (verbose > 0)
258 Utils.log.info("archiveOptions = "
259 +"0b"+Integer.toBinaryString(archiveOptions));
260 }
261
262 void writeFileHeader() throws IOException {
263 pkg.checkVersion();
264 writeArchiveMagic();
265 writeArchiveHeader();
266 }
267
268
269
270 private void putMagicInt32(int val) throws IOException {
271 int res = val;
272 for (int i = 0; i < 4; i++) {
273 archive_magic.putByte(0xFF & (res >>> 24));
274 res <<= 8;
275 }
276 }
277
278 void writeArchiveMagic() throws IOException {
279 putMagicInt32(pkg.magic);
280 }
281
282 void writeArchiveHeader() throws IOException {
283
284 int headerDiscountForDebug = 0;
285
286
287
288
289 boolean haveSpecial = testBit(archiveOptions, AO_HAVE_SPECIAL_FORMATS);
290 if (!haveSpecial) {
291 haveSpecial |= (band_headers.length() != 0);
292 haveSpecial |= (attrDefsWritten.length != 0);
293 if (haveSpecial)
294 archiveOptions |= AO_HAVE_SPECIAL_FORMATS;
295 }
296 if (!haveSpecial)
297 headerDiscountForDebug += AH_SPECIAL_FORMAT_LEN;
298
299
300
301 boolean haveFiles = testBit(archiveOptions, AO_HAVE_FILE_HEADERS);
302 if (!haveFiles) {
303 haveFiles |= (archiveNextCount > 0);
304 haveFiles |= (pkg.default_modtime != NO_MODTIME);
305 if (haveFiles)
306 archiveOptions |= AO_HAVE_FILE_HEADERS;
307 }
308 if (!haveFiles)
309 headerDiscountForDebug += AH_FILE_HEADER_LEN;
310
311
312
313 boolean haveNumbers = testBit(archiveOptions, AO_HAVE_CP_NUMBERS);
314 if (!haveNumbers) {
315 haveNumbers |= pkg.cp.haveNumbers();
316 if (haveNumbers)
317 archiveOptions |= AO_HAVE_CP_NUMBERS;
318 }
319 if (!haveNumbers)
320 headerDiscountForDebug += AH_CP_NUMBER_LEN;
321
322 assert(pkg.package_majver > 0);
323 archive_header_0.putInt(pkg.package_minver);
324 archive_header_0.putInt(pkg.package_majver);
325 if (verbose > 0)
326 Utils.log.info("Package Version for this segment:"+
327 Package.versionStringOf(pkg.getPackageVersion()));
328 archive_header_0.putInt(archiveOptions);
329 assert(archive_header_0.length() == AH_LENGTH_0);
330
331 final int DUMMY = 0;
332 if (haveFiles) {
333 assert(archive_header_S.length() == AH_ARCHIVE_SIZE_HI);
334 archive_header_S.putInt(DUMMY);
335 assert(archive_header_S.length() == AH_ARCHIVE_SIZE_LO);
336 archive_header_S.putInt(DUMMY);
337 assert(archive_header_S.length() == AH_LENGTH_S);
338 }
339
340
341
342 if (haveFiles) {
343 archive_header_1.putInt(archiveNextCount);
344 archive_header_1.putInt(pkg.default_modtime);
345 archive_header_1.putInt(pkg.files.size());
346 } else {
347 assert(pkg.files.isEmpty());
348 }
349
350 if (haveSpecial) {
351 archive_header_1.putInt(band_headers.length());
352 archive_header_1.putInt(attrDefsWritten.length);
353 } else {
354 assert(band_headers.length() == 0);
355 assert(attrDefsWritten.length == 0);
356 }
357
358 writeConstantPoolCounts(haveNumbers);
359
360 archive_header_1.putInt(pkg.getAllInnerClasses().size());
361 archive_header_1.putInt(pkg.default_class_minver);
362 archive_header_1.putInt(pkg.default_class_majver);
363 archive_header_1.putInt(pkg.classes.size());
364
365
366 assert(archive_header_0.length() +
367 archive_header_S.length() +
368 archive_header_1.length()
369 == AH_LENGTH - headerDiscountForDebug);
370
371
372 archiveSize0 = 0;
373 archiveSize1 = all_bands.outputSize();
374
375 archiveSize0 += archive_magic.outputSize();
376 archiveSize0 += archive_header_0.outputSize();
377 archiveSize0 += archive_header_S.outputSize();
378
379 archiveSize1 -= archiveSize0;
380
381
382 if (haveFiles) {
383 int archiveSizeHi = (int)(archiveSize1 >>> 32);
384 int archiveSizeLo = (int)(archiveSize1 >>> 0);
385 archive_header_S.patchValue(AH_ARCHIVE_SIZE_HI, archiveSizeHi);
386 archive_header_S.patchValue(AH_ARCHIVE_SIZE_LO, archiveSizeLo);
387 int zeroLen = UNSIGNED5.getLength(DUMMY);
388 archiveSize0 += UNSIGNED5.getLength(archiveSizeHi) - zeroLen;
389 archiveSize0 += UNSIGNED5.getLength(archiveSizeLo) - zeroLen;
390 }
391 if (verbose > 1)
392 Utils.log.fine("archive sizes: "+
393 archiveSize0+"+"+archiveSize1);
394 assert(all_bands.outputSize() == archiveSize0+archiveSize1);
395 }
396
397 void writeConstantPoolCounts(boolean haveNumbers) throws IOException {
398 for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) {
399 byte tag = ConstantPool.TAGS_IN_ORDER[k];
400 int count = pkg.cp.getIndexByTag(tag).size();
401 switch (tag) {
402 case CONSTANT_Utf8:
403
404 if (count > 0)
405 assert(pkg.cp.getIndexByTag(tag).get(0)
406 == ConstantPool.getUtf8Entry(""));
407 break;
408
409 case CONSTANT_Integer:
410 case CONSTANT_Float:
411 case CONSTANT_Long:
412 case CONSTANT_Double:
413
414 if (!haveNumbers) {
415 assert(count == 0);
416 continue;
417 }
418 break;
419 }
420 archive_header_1.putInt(count);
421 }
422 }
423
424 protected Index getCPIndex(byte tag) {
425 return pkg.cp.getIndexByTag(tag);
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447 void writeConstantPool() throws IOException {
448 IndexGroup cp = pkg.cp;
449
450 if (verbose > 0) Utils.log.info("Writing CP");
451
452 for (int k = 0; k < ConstantPool.TAGS_IN_ORDER.length; k++) {
453 byte tag = ConstantPool.TAGS_IN_ORDER[k];
454 Index index = cp.getIndexByTag(tag);
455
456 Entry[] cpMap = index.cpMap;
457 if (verbose > 0)
458 Utils.log.info("Writing "+cpMap.length+" "+ConstantPool.tagName(tag)+" entries...");
459
460 if (optDumpBands) {
461 try (PrintStream ps = new PrintStream(getDumpStream(index, ".idx"))) {
462 printArrayTo(ps, cpMap, 0, cpMap.length);
463 }
464 }
465
466 switch (tag) {
467 case CONSTANT_Utf8:
468 writeUtf8Bands(cpMap);
469 break;
470 case CONSTANT_Integer:
471 for (int i = 0; i < cpMap.length; i++) {
472 NumberEntry e = (NumberEntry) cpMap[i];
473 int x = ((Integer)e.numberValue()).intValue();
474 cp_Int.putInt(x);
475 }
476 break;
477 case CONSTANT_Float:
478 for (int i = 0; i < cpMap.length; i++) {
479 NumberEntry e = (NumberEntry) cpMap[i];
480 float fx = ((Float)e.numberValue()).floatValue();
481 int x = Float.floatToIntBits(fx);
482 cp_Float.putInt(x);
483 }
484 break;
485 case CONSTANT_Long:
486 for (int i = 0; i < cpMap.length; i++) {
487 NumberEntry e = (NumberEntry) cpMap[i];
488 long x = ((Long)e.numberValue()).longValue();
489 cp_Long_hi.putInt((int)(x >>> 32));
490 cp_Long_lo.putInt((int)(x >>> 0));
491 }
492 break;
493 case CONSTANT_Double:
494 for (int i = 0; i < cpMap.length; i++) {
495 NumberEntry e = (NumberEntry) cpMap[i];
496 double dx = ((Double)e.numberValue()).doubleValue();
497 long x = Double.doubleToLongBits(dx);
498 cp_Double_hi.putInt((int)(x >>> 32));
499 cp_Double_lo.putInt((int)(x >>> 0));
500 }
501 break;
502 case CONSTANT_String:
503 for (int i = 0; i < cpMap.length; i++) {
504 StringEntry e = (StringEntry) cpMap[i];
505 cp_String.putRef(e.ref);
506 }
507 break;
508 case CONSTANT_Class:
509 for (int i = 0; i < cpMap.length; i++) {
510 ClassEntry e = (ClassEntry) cpMap[i];
511 cp_Class.putRef(e.ref);
512 }
513 break;
514 case CONSTANT_Signature:
515 writeSignatureBands(cpMap);
516 break;
517 case CONSTANT_NameandType:
518 for (int i = 0; i < cpMap.length; i++) {
519 DescriptorEntry e = (DescriptorEntry) cpMap[i];
520 cp_Descr_name.putRef(e.nameRef);
521 cp_Descr_type.putRef(e.typeRef);
522 }
523 break;
524 case CONSTANT_Fieldref:
525 writeMemberRefs(tag, cpMap, cp_Field_class, cp_Field_desc);
526 break;
527 case CONSTANT_Methodref:
528 writeMemberRefs(tag, cpMap, cp_Method_class, cp_Method_desc);
529 break;
530 case CONSTANT_InterfaceMethodref:
531 writeMemberRefs(tag, cpMap, cp_Imethod_class, cp_Imethod_desc);
532 break;
533 default:
534 assert(false);
535 }
536 }
537 }
538
539 void writeUtf8Bands(Entry[] cpMap) throws IOException {
540 if (cpMap.length == 0)
541 return;
542
543
544 assert(cpMap[0].stringValue().equals(""));
545 final int SUFFIX_SKIP_1 = 1;
546 final int PREFIX_SKIP_2 = 2;
547
548
549 char[][] chars = new char[cpMap.length][];
550 for (int i = 0; i < chars.length; i++) {
551 chars[i] = cpMap[i].stringValue().toCharArray();
552 }
553
554
555 int[] prefixes = new int[cpMap.length];
556 char[] prevChars = {};
557 for (int i = 0; i < chars.length; i++) {
558 int prefix = 0;
559 char[] curChars = chars[i];
560 int limit = Math.min(curChars.length, prevChars.length);
561 while (prefix < limit && curChars[prefix] == prevChars[prefix])
562 prefix++;
563 prefixes[i] = prefix;
564 if (i >= PREFIX_SKIP_2)
565 cp_Utf8_prefix.putInt(prefix);
566 else
567 assert(prefix == 0);
568 prevChars = curChars;
569 }
570
571
572
573 for (int i = 0; i < chars.length; i++) {
574 char[] str = chars[i];
575 int prefix = prefixes[i];
576 int suffix = str.length - prefixes[i];
577 boolean isPacked = false;
578 if (suffix == 0) {
579
580
581
582
583
584
585
586
587 isPacked = (i >= SUFFIX_SKIP_1);
588
589
590 } else if (optBigStrings && effort > 1 && suffix > 100) {
591 int numWide = 0;
592 for (int n = 0; n < suffix; n++) {
593 if (str[prefix+n] > 127) {
594 numWide++;
595 }
596 }
597 if (numWide > 100) {
598
599 isPacked = tryAlternateEncoding(i, numWide, str, prefix);
600 }
601 }
602 if (i < SUFFIX_SKIP_1) {
603
604 assert(!isPacked);
605 assert(suffix == 0);
606 } else if (isPacked) {
607
608
609
610 cp_Utf8_suffix.putInt(0);
611 cp_Utf8_big_suffix.putInt(suffix);
612 } else {
613 assert(suffix != 0);
614
615 cp_Utf8_suffix.putInt(suffix);
616 for (int n = 0; n < suffix; n++) {
617 int ch = str[prefix+n];
618 cp_Utf8_chars.putInt(ch);
619 }
620 }
621 }
622 if (verbose > 0) {
623 int normCharCount = cp_Utf8_chars.length();
624 int packCharCount = cp_Utf8_big_chars.length();
625 int charCount = normCharCount + packCharCount;
626 Utils.log.info("Utf8string #CHARS="+charCount+" #PACKEDCHARS="+packCharCount);
627 }
628 }
629
630 private boolean tryAlternateEncoding(int i, int numWide,
631 char[] str, int prefix) {
632 int suffix = str.length - prefix;
633 int[] cvals = new int[suffix];
634 for (int n = 0; n < suffix; n++) {
635 cvals[n] = str[prefix+n];
636 }
637 CodingChooser cc = getCodingChooser();
638 Coding bigRegular = cp_Utf8_big_chars.regularCoding;
639 String bandName = "(Utf8_big_"+i+")";
640 int[] sizes = { 0, 0 };
641 final int BYTE_SIZE = CodingChooser.BYTE_SIZE;
642 final int ZIP_SIZE = CodingChooser.ZIP_SIZE;
643 if (verbose > 1 || cc.verbose > 1) {
644 Utils.log.fine("--- chooseCoding "+bandName);
645 }
646 CodingMethod special = cc.choose(cvals, bigRegular, sizes);
647 Coding charRegular = cp_Utf8_chars.regularCoding;
648 if (verbose > 1)
649 Utils.log.fine("big string["+i+"] len="+suffix+" #wide="+numWide+" size="+sizes[BYTE_SIZE]+"/z="+sizes[ZIP_SIZE]+" coding "+special);
650 if (special != charRegular) {
651 int specialZipSize = sizes[ZIP_SIZE];
652 int[] normalSizes = cc.computeSize(charRegular, cvals);
653 int normalZipSize = normalSizes[ZIP_SIZE];
654 int minWin = Math.max(5, normalZipSize/1000);
655 if (verbose > 1)
656 Utils.log.fine("big string["+i+"] normalSize="+normalSizes[BYTE_SIZE]+"/z="+normalSizes[ZIP_SIZE]+" win="+(specialZipSize<normalZipSize-minWin));
657 if (specialZipSize < normalZipSize-minWin) {
658 IntBand big = cp_Utf8_big_chars.newIntBand(bandName);
659 big.initializeValues(cvals);
660 return true;
661 }
662 }
663 return false;
664 }
665
666 void writeSignatureBands(Entry[] cpMap) throws IOException {
667 for (int i = 0; i < cpMap.length; i++) {
668 SignatureEntry e = (SignatureEntry) cpMap[i];
669 cp_Signature_form.putRef(e.formRef);
670 for (int j = 0; j < e.classRefs.length; j++) {
671 cp_Signature_classes.putRef(e.classRefs[j]);
672 }
673 }
674 }
675
676 void writeMemberRefs(byte tag, Entry[] cpMap, CPRefBand cp_class, CPRefBand cp_desc) throws IOException {
677 for (int i = 0; i < cpMap.length; i++) {
678 MemberEntry e = (MemberEntry) cpMap[i];
679 cp_class.putRef(e.classRef);
680 cp_desc.putRef(e.descRef);
681 }
682 }
683
684 void writeFiles() throws IOException {
685 int numFiles = pkg.files.size();
686 if (numFiles == 0) return;
687 int options = archiveOptions;
688 boolean haveSizeHi = testBit(options, AO_HAVE_FILE_SIZE_HI);
689 boolean haveModtime = testBit(options, AO_HAVE_FILE_MODTIME);
690 boolean haveOptions = testBit(options, AO_HAVE_FILE_OPTIONS);
691 if (!haveOptions) {
692 for (File file : pkg.files) {
693 if (file.isClassStub()) {
694 haveOptions = true;
695 options |= AO_HAVE_FILE_OPTIONS;
696 archiveOptions = options;
697 break;
698 }
699 }
700 }
701 if (haveSizeHi || haveModtime || haveOptions || !pkg.files.isEmpty()) {
702 options |= AO_HAVE_FILE_HEADERS;
703 archiveOptions = options;
704 }
705 for (File file : pkg.files) {
706 file_name.putRef(file.name);
707 long len = file.getFileLength();
708 file_size_lo.putInt((int)len);
709 if (haveSizeHi)
710 file_size_hi.putInt((int)(len >>> 32));
711 if (haveModtime)
712 file_modtime.putInt(file.modtime - pkg.default_modtime);
713 if (haveOptions)
714 file_options.putInt(file.options);
715 file.writeTo(file_bits.collectorStream());
716 if (verbose > 1)
717 Utils.log.fine("Wrote "+len+" bytes of "+file.name.stringValue());
718 }
719 if (verbose > 0)
720 Utils.log.info("Wrote "+numFiles+" resource files");
721 }
722
723 @SuppressWarnings("unchecked")
724 void collectAttributeLayouts() {
725 maxFlags = new int[ATTR_CONTEXT_LIMIT];
726 allLayouts = new FixedList<>(ATTR_CONTEXT_LIMIT);
727 for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
728 allLayouts.set(i, new HashMap<Attribute.Layout, int[]>());
729 }
730
731 for (Class cls : pkg.classes) {
732 visitAttributeLayoutsIn(ATTR_CONTEXT_CLASS, cls);
733 for (Class.Field f : cls.getFields()) {
734 visitAttributeLayoutsIn(ATTR_CONTEXT_FIELD, f);
735 }
736 for (Class.Method m : cls.getMethods()) {
737 visitAttributeLayoutsIn(ATTR_CONTEXT_METHOD, m);
738 if (m.code != null) {
739 visitAttributeLayoutsIn(ATTR_CONTEXT_CODE, m.code);
740 }
741 }
742 }
743
744 for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
745 int nl = allLayouts.get(i).size();
746 boolean haveLongFlags = haveFlagsHi(i);
747 final int TOO_MANY_ATTRS = 32
748 - 12
749 + 4 ;
750 if (nl >= TOO_MANY_ATTRS) {
751 int mask = 1<<(LG_AO_HAVE_XXX_FLAGS_HI+i);
752 archiveOptions |= mask;
753 haveLongFlags = true;
754 if (verbose > 0)
755 Utils.log.info("Note: Many "+Attribute.contextName(i)+" attributes forces 63-bit flags");
756 }
757 if (verbose > 1) {
758 Utils.log.fine(Attribute.contextName(i)+".maxFlags = 0x"+Integer.toHexString(maxFlags[i]));
759 Utils.log.fine(Attribute.contextName(i)+".#layouts = "+nl);
760 }
761 assert(haveFlagsHi(i) == haveLongFlags);
762 }
763 initAttrIndexLimit();
764
765
766 for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
767 assert((attrFlagMask[i] & maxFlags[i]) == 0);
768 }
769
770
771 backCountTable = new HashMap<>();
772 attrCounts = new int[ATTR_CONTEXT_LIMIT][];
773 for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
774
775
776
777
778 long avHiBits = ~(maxFlags[i] | attrFlagMask[i]);
779 assert(attrIndexLimit[i] > 0);
780 assert(attrIndexLimit[i] < 64);
781 avHiBits &= (1L<<attrIndexLimit[i])-1;
782 int nextLoBit = 0;
783 Map<Attribute.Layout, int[]> defMap = allLayouts.get(i);
784 Map.Entry[] layoutsAndCounts = new Map.Entry[defMap.size()];
785 defMap.entrySet().toArray(layoutsAndCounts);
786
787
788 Arrays.sort(layoutsAndCounts, new Comparator<Object>() {
789 public int compare(Object o0, Object o1) {
790 Map.Entry e0 = (Map.Entry) o0;
791 Map.Entry e1 = (Map.Entry) o1;
792
793 int r = - ( ((int[])e0.getValue())[0]
794 - ((int[])e1.getValue())[0] );
795 if (r != 0) return r;
796 return ((Comparable)e0.getKey()).compareTo(e1.getKey());
797 }
798 });
799 attrCounts[i] = new int[attrIndexLimit[i]+layoutsAndCounts.length];
800 for (int j = 0; j < layoutsAndCounts.length; j++) {
801 Map.Entry e = layoutsAndCounts[j];
802 Attribute.Layout def = (Attribute.Layout) e.getKey();
803 int count = ((int[])e.getValue())[0];
804 int index;
805 Integer predefIndex = attrIndexTable.get(def);
806 if (predefIndex != null) {
807
808 index = predefIndex.intValue();
809 } else if (avHiBits != 0) {
810 while ((avHiBits & 1) == 0) {
811 avHiBits >>>= 1;
812 nextLoBit += 1;
813 }
814 avHiBits -= 1;
815
816 index = setAttributeLayoutIndex(def, nextLoBit);
817 } else {
818
819 index = setAttributeLayoutIndex(def, ATTR_INDEX_OVERFLOW);
820 }
821
822
823 attrCounts[i][index] = count;
824
825
826 Attribute.Layout.Element[] cbles = def.getCallables();
827 final int[] bc = new int[cbles.length];
828 for (int k = 0; k < cbles.length; k++) {
829 assert(cbles[k].kind == Attribute.EK_CBLE);
830 if (!cbles[k].flagTest(Attribute.EF_BACK)) {
831 bc[k] = -1;
832 }
833 }
834 backCountTable.put(def, bc);
835
836 if (predefIndex == null) {
837
838 Entry ne = ConstantPool.getUtf8Entry(def.name());
839 String layout = def.layoutForPackageMajver(getPackageMajver());
840 Entry le = ConstantPool.getUtf8Entry(layout);
841 requiredEntries.add(ne);
842 requiredEntries.add(le);
843 if (verbose > 0) {
844 if (index < attrIndexLimit[i])
845 Utils.log.info("Using free flag bit 1<<"+index+" for "+count+" occurrences of "+def);
846 else
847 Utils.log.info("Using overflow index "+index+" for "+count+" occurrences of "+def);
848 }
849 }
850 }
851 }
852
853
854
855
856
857 maxFlags = null;
858 allLayouts = null;
859 }
860
861
862 int[] maxFlags;
863 List<Map<Attribute.Layout, int[]>> allLayouts;
864
865 void visitAttributeLayoutsIn(int ctype, Attribute.Holder h) {
866
867
868 maxFlags[ctype] |= h.flags;
869 for (Attribute a : h.getAttributes()) {
870 Attribute.Layout def = a.layout();
871 Map<Attribute.Layout, int[]> defMap = allLayouts.get(ctype);
872 int[] count = defMap.get(def);
873 if (count == null) {
874 defMap.put(def, count = new int[1]);
875 }
876 if (count[0] < Integer.MAX_VALUE) {
877 count[0] += 1;
878 }
879 }
880 }
881
882 Attribute.Layout[] attrDefsWritten;
883
884 @SuppressWarnings("unchecked")
885 void writeAttrDefs() throws IOException {
886 List<Object[]> defList = new ArrayList<>();
887 for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
888 int limit = attrDefs.get(i).size();
889 for (int j = 0; j < limit; j++) {
890 int header = i;
891 if (j < attrIndexLimit[i]) {
892 header |= ((j + ADH_BIT_IS_LSB) << ADH_BIT_SHIFT);
893 assert(header < 0x100);
894
895 if (!testBit(attrDefSeen[i], 1L<<j)) {
896
897 continue;
898 }
899 }
900 Attribute.Layout def = attrDefs.get(i).get(j);
901 defList.add(new Object[]{ Integer.valueOf(header), def });
902 assert(Integer.valueOf(j).equals(attrIndexTable.get(def)));
903 }
904 }
905
906 int numAttrDefs = defList.size();
907 Object[][] defs = new Object[numAttrDefs][];
908 defList.toArray(defs);
909 Arrays.sort(defs, new Comparator() {
910 public int compare(Object o0, Object o1) {
911 Object[] a0 = (Object[]) o0;
912 Object[] a1 = (Object[]) o1;
913
914 int r = ((Comparable)a0[0]).compareTo(a1[0]);
915 if (r != 0) return r;
916 Object ind0 = attrIndexTable.get(a0[1]);
917 Object ind1 = attrIndexTable.get(a1[1]);
918
919
920 assert(ind0 != null);
921 assert(ind1 != null);
922 return ((Comparable)ind0).compareTo(ind1);
923 }
924 });
925 attrDefsWritten = new Attribute.Layout[numAttrDefs];
926 try (PrintStream dump = !optDumpBands ? null
927 : new PrintStream(getDumpStream(attr_definition_headers, ".def")))
928 {
929 int[] indexForDebug = Arrays.copyOf(attrIndexLimit, ATTR_CONTEXT_LIMIT);
930 for (int i = 0; i < defs.length; i++) {
931 int header = ((Integer)defs[i][0]).intValue();
932 Attribute.Layout def = (Attribute.Layout) defs[i][1];
933 attrDefsWritten[i] = def;
934 assert((header & ADH_CONTEXT_MASK) == def.ctype());
935 attr_definition_headers.putByte(header);
936 attr_definition_name.putRef(ConstantPool.getUtf8Entry(def.name()));
937 String layout = def.layoutForPackageMajver(getPackageMajver());
938 attr_definition_layout.putRef(ConstantPool.getUtf8Entry(layout));
939
940 boolean debug = false;
941 assert(debug = true);
942 if (debug) {
943 int hdrIndex = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB;
944 if (hdrIndex < 0) hdrIndex = indexForDebug[def.ctype()]++;
945 int realIndex = (attrIndexTable.get(def)).intValue();
946 assert(hdrIndex == realIndex);
947 }
948 if (dump != null) {
949 int index = (header >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB;
950 dump.println(index+" "+def);
951 }
952 }
953 }
954 }
955
956 void writeAttrCounts() throws IOException {
957
958 for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
959 MultiBand xxx_attr_bands = attrBands[ctype];
960 IntBand xxx_attr_calls = getAttrBand(xxx_attr_bands, AB_ATTR_CALLS);
961 Attribute.Layout[] defs = new Attribute.Layout[attrDefs.get(ctype).size()];
962 attrDefs.get(ctype).toArray(defs);
963 for (boolean predef = true; ; predef = false) {
964 for (int ai = 0; ai < defs.length; ai++) {
965 Attribute.Layout def = defs[ai];
966 if (def == null) continue;
967 if (predef != isPredefinedAttr(ctype, ai))
968 continue;
969 int totalCount = attrCounts[ctype][ai];
970 if (totalCount == 0)
971 continue;
972 int[] bc = backCountTable.get(def);
973 for (int j = 0; j < bc.length; j++) {
974 if (bc[j] >= 0) {
975 int backCount = bc[j];
976 bc[j] = -1;
977 xxx_attr_calls.putInt(backCount);
978 assert(def.getCallables()[j].flagTest(Attribute.EF_BACK));
979 } else {
980 assert(!def.getCallables()[j].flagTest(Attribute.EF_BACK));
981 }
982 }
983 }
984 if (!predef) break;
985 }
986 }
987 }
988
989 void trimClassAttributes() {
990 for (Class cls : pkg.classes) {
991
992 cls.minimizeSourceFile();
993 }
994 }
995
996 void collectInnerClasses() {
997
998
999 Map<ClassEntry, InnerClass> allICMap = new HashMap<>();
1000
1001 for (Class cls : pkg.classes) {
1002 if (!cls.hasInnerClasses()) continue;
1003 for (InnerClass ic : cls.getInnerClasses()) {
1004 InnerClass pic = allICMap.put(ic.thisClass, ic);
1005 if (pic != null && !pic.equals(ic) && pic.predictable) {
1006
1007 allICMap.put(pic.thisClass, pic);
1008 }
1009 }
1010 }
1011
1012 InnerClass[] allICs = new InnerClass[allICMap.size()];
1013 allICMap.values().toArray(allICs);
1014 allICMap = null;
1015
1016
1017
1018
1019 Arrays.sort(allICs);
1020 pkg.setAllInnerClasses(Arrays.asList(allICs));
1021
1022
1023
1024
1025 for (Class cls : pkg.classes) {
1026 cls.minimizeLocalICs();
1027 }
1028 }
1029
1030 void writeInnerClasses() throws IOException {
1031 for (InnerClass ic : pkg.getAllInnerClasses()) {
1032 int flags = ic.flags;
1033 assert((flags & ACC_IC_LONG_FORM) == 0);
1034 if (!ic.predictable) {
1035 flags |= ACC_IC_LONG_FORM;
1036 }
1037 ic_this_class.putRef(ic.thisClass);
1038 ic_flags.putInt(flags);
1039 if (!ic.predictable) {
1040 ic_outer_class.putRef(ic.outerClass);
1041 ic_name.putRef(ic.name);
1042 }
1043 }
1044 }
1045
1046
1047
1048
1049
1050 void writeLocalInnerClasses(Class cls) throws IOException {
1051 List<InnerClass> localICs = cls.getInnerClasses();
1052 class_InnerClasses_N.putInt(localICs.size());
1053 for(InnerClass ic : localICs) {
1054 class_InnerClasses_RC.putRef(ic.thisClass);
1055
1056 if (ic.equals(pkg.getGlobalInnerClass(ic.thisClass))) {
1057
1058 class_InnerClasses_F.putInt(0);
1059 } else {
1060 int flags = ic.flags;
1061 if (flags == 0)
1062 flags = ACC_IC_LONG_FORM;
1063 class_InnerClasses_F.putInt(flags);
1064 class_InnerClasses_outer_RCN.putRef(ic.outerClass);
1065 class_InnerClasses_name_RUN.putRef(ic.name);
1066 }
1067 }
1068 }
1069
1070 void writeClassesAndByteCodes() throws IOException {
1071 Class[] classes = new Class[pkg.classes.size()];
1072 pkg.classes.toArray(classes);
1073
1074 if (verbose > 0)
1075 Utils.log.info(" ...scanning "+classes.length+" classes...");
1076
1077 int nwritten = 0;
1078 for (int i = 0; i < classes.length; i++) {
1079
1080 Class cls = classes[i];
1081 if (verbose > 1)
1082 Utils.log.fine("Scanning "+cls);
1083
1084 ClassEntry thisClass = cls.thisClass;
1085 ClassEntry superClass = cls.superClass;
1086 ClassEntry[] interfaces = cls.interfaces;
1087
1088 assert(superClass != thisClass);
1089 if (superClass == null) superClass = thisClass;
1090 class_this.putRef(thisClass);
1091 class_super.putRef(superClass);
1092 class_interface_count.putInt(cls.interfaces.length);
1093 for (int j = 0; j < interfaces.length; j++) {
1094 class_interface.putRef(interfaces[j]);
1095 }
1096
1097 writeMembers(cls);
1098 writeAttrs(ATTR_CONTEXT_CLASS, cls, cls);
1099
1100 nwritten++;
1101 if (verbose > 0 && (nwritten % 1000) == 0)
1102 Utils.log.info("Have scanned "+nwritten+" classes...");
1103 }
1104 }
1105
1106 void writeMembers(Class cls) throws IOException {
1107 List<Class.Field> fields = cls.getFields();
1108 class_field_count.putInt(fields.size());
1109 for (Class.Field f : fields) {
1110 field_descr.putRef(f.getDescriptor());
1111 writeAttrs(ATTR_CONTEXT_FIELD, f, cls);
1112 }
1113
1114 List<Class.Method> methods = cls.getMethods();
1115 class_method_count.putInt(methods.size());
1116 for (Class.Method m : methods) {
1117 method_descr.putRef(m.getDescriptor());
1118 writeAttrs(ATTR_CONTEXT_METHOD, m, cls);
1119 assert((m.code != null) == (m.getAttribute(attrCodeEmpty) != null));
1120 if (m.code != null) {
1121 writeCodeHeader(m.code);
1122 writeByteCodes(m.code);
1123 }
1124 }
1125 }
1126
1127 void writeCodeHeader(Code c) throws IOException {
1128 boolean attrsOK = testBit(archiveOptions, AO_HAVE_ALL_CODE_FLAGS);
1129 int na = c.attributeSize();
1130 int sc = shortCodeHeader(c);
1131 if (!attrsOK && na > 0)
1132
1133 sc = LONG_CODE_HEADER;
1134 if (verbose > 2) {
1135 int siglen = c.getMethod().getArgumentSize();
1136 Utils.log.fine("Code sizes info "+c.max_stack+" "+c.max_locals+" "+c.getHandlerCount()+" "+siglen+" "+na+(sc > 0 ? " SHORT="+sc : ""));
1137 }
1138 code_headers.putByte(sc);
1139 if (sc == LONG_CODE_HEADER) {
1140 code_max_stack.putInt(c.getMaxStack());
1141 code_max_na_locals.putInt(c.getMaxNALocals());
1142 code_handler_count.putInt(c.getHandlerCount());
1143 } else {
1144 assert(attrsOK || na == 0);
1145 assert(c.getHandlerCount() < shortCodeHeader_h_limit);
1146 }
1147 writeCodeHandlers(c);
1148 if (sc == LONG_CODE_HEADER || attrsOK)
1149 writeAttrs(ATTR_CONTEXT_CODE, c, c.thisClass());
1150 }
1151
1152 void writeCodeHandlers(Code c) throws IOException {
1153 int sum, del;
1154 for (int j = 0, jmax = c.getHandlerCount(); j < jmax; j++) {
1155 code_handler_class_RCN.putRef(c.handler_class[j]);
1156
1157
1158 sum = c.encodeBCI(c.handler_start[j]);
1159 code_handler_start_P.putInt(sum);
1160 del = c.encodeBCI(c.handler_end[j]) - sum;
1161 code_handler_end_PO.putInt(del);
1162 sum += del;
1163 del = c.encodeBCI(c.handler_catch[j]) - sum;
1164 code_handler_catch_PO.putInt(del);
1165 }
1166 }
1167
1168
1169
1170 void writeAttrs(int ctype,
1171 final Attribute.Holder h,
1172 Class cls) throws IOException {
1173 MultiBand xxx_attr_bands = attrBands[ctype];
1174 IntBand xxx_flags_hi = getAttrBand(xxx_attr_bands, AB_FLAGS_HI);
1175 IntBand xxx_flags_lo = getAttrBand(xxx_attr_bands, AB_FLAGS_LO);
1176 boolean haveLongFlags = haveFlagsHi(ctype);
1177 assert(attrIndexLimit[ctype] == (haveLongFlags? 63: 32));
1178 if (h.attributes == null) {
1179 xxx_flags_lo.putInt(h.flags);
1180 if (haveLongFlags)
1181 xxx_flags_hi.putInt(0);
1182 return;
1183 }
1184 if (verbose > 3)
1185 Utils.log.fine("Transmitting attrs for "+h+" flags="+Integer.toHexString(h.flags));
1186
1187 long flagMask = attrFlagMask[ctype];
1188 long flagsToAdd = 0;
1189 int overflowCount = 0;
1190 for (Attribute a : h.attributes) {
1191 Attribute.Layout def = a.layout();
1192 int index = (attrIndexTable.get(def)).intValue();
1193 assert(attrDefs.get(ctype).get(index) == def);
1194 if (verbose > 3)
1195 Utils.log.fine("add attr @"+index+" "+a+" in "+h);
1196 if (index < attrIndexLimit[ctype] && testBit(flagMask, 1L<<index)) {
1197 if (verbose > 3)
1198 Utils.log.fine("Adding flag bit 1<<"+index+" in "+Long.toHexString(flagMask));
1199 assert(!testBit(h.flags, 1L<<index));
1200 flagsToAdd |= (1L<<index);
1201 flagMask -= (1L<<index);
1202 } else {
1203
1204 flagsToAdd |= (1L<<X_ATTR_OVERFLOW);
1205 overflowCount += 1;
1206 if (verbose > 3)
1207 Utils.log.fine("Adding overflow attr #"+overflowCount);
1208 IntBand xxx_attr_indexes = getAttrBand(xxx_attr_bands, AB_ATTR_INDEXES);
1209 xxx_attr_indexes.putInt(index);
1210
1211 }
1212 if (def.bandCount == 0) {
1213 if (def == attrInnerClassesEmpty) {
1214
1215 writeLocalInnerClasses((Class) h);
1216 continue;
1217 }
1218
1219 continue;
1220 }
1221 assert(a.fixups == null);
1222 final Band[] ab = attrBandTable.get(def);
1223 assert(ab != null);
1224 assert(ab.length == def.bandCount);
1225 final int[] bc = backCountTable.get(def);
1226 assert(bc != null);
1227 assert(bc.length == def.getCallables().length);
1228
1229 if (verbose > 2) Utils.log.fine("writing "+a+" in "+h);
1230 boolean isCV = (ctype == ATTR_CONTEXT_FIELD && def == attrConstantValue);
1231 if (isCV) setConstantValueIndex((Class.Field)h);
1232 a.parse(cls, a.bytes(), 0, a.size(),
1233 new Attribute.ValueStream() {
1234 public void putInt(int bandIndex, int value) {
1235 ((IntBand) ab[bandIndex]).putInt(value);
1236 }
1237 public void putRef(int bandIndex, Entry ref) {
1238 ((CPRefBand) ab[bandIndex]).putRef(ref);
1239 }
1240 public int encodeBCI(int bci) {
1241 Code code = (Code) h;
1242 return code.encodeBCI(bci);
1243 }
1244 public void noteBackCall(int whichCallable) {
1245 assert(bc[whichCallable] >= 0);
1246 bc[whichCallable] += 1;
1247 }
1248 });
1249 if (isCV) setConstantValueIndex(null);
1250 }
1251
1252 if (overflowCount > 0) {
1253 IntBand xxx_attr_count = getAttrBand(xxx_attr_bands, AB_ATTR_COUNT);
1254 xxx_attr_count.putInt(overflowCount);
1255 }
1256
1257 xxx_flags_lo.putInt(h.flags | (int)flagsToAdd);
1258 if (haveLongFlags)
1259 xxx_flags_hi.putInt((int)(flagsToAdd >>> 32));
1260 else
1261 assert((flagsToAdd >>> 32) == 0);
1262 assert((h.flags & flagsToAdd) == 0)
1263 : (h+".flags="
1264 +Integer.toHexString(h.flags)+"^"
1265 +Long.toHexString(flagsToAdd));
1266 }
1267
1268
1269 private Code curCode;
1270 private Class curClass;
1271 private Entry[] curCPMap;
1272 private void beginCode(Code c) {
1273 assert(curCode == null);
1274 curCode = c;
1275 curClass = c.m.thisClass();
1276 curCPMap = c.getCPMap();
1277 }
1278 private void endCode() {
1279 curCode = null;
1280 curClass = null;
1281 curCPMap = null;
1282 }
1283
1284
1285
1286 private int initOpVariant(Instruction i, Entry newClass) {
1287 if (i.getBC() != _invokespecial) return -1;
1288 MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1289 if ("<init>".equals(ref.descRef.nameRef.stringValue()) == false)
1290 return -1;
1291 ClassEntry refClass = ref.classRef;
1292 if (refClass == curClass.thisClass)
1293 return _invokeinit_op+_invokeinit_self_option;
1294 if (refClass == curClass.superClass)
1295 return _invokeinit_op+_invokeinit_super_option;
1296 if (refClass == newClass)
1297 return _invokeinit_op+_invokeinit_new_option;
1298 return -1;
1299 }
1300
1301
1302
1303 private int selfOpVariant(Instruction i) {
1304 int bc = i.getBC();
1305 if (!(bc >= _first_linker_op && bc <= _last_linker_op)) return -1;
1306 MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1307 ClassEntry refClass = ref.classRef;
1308 int self_bc = _self_linker_op + (bc - _first_linker_op);
1309 if (refClass == curClass.thisClass)
1310 return self_bc;
1311 if (refClass == curClass.superClass)
1312 return self_bc + _self_linker_super_flag;
1313 return -1;
1314 }
1315
1316 void writeByteCodes(Code code) throws IOException {
1317 beginCode(code);
1318 IndexGroup cp = pkg.cp;
1319
1320
1321 boolean prevAload = false;
1322
1323
1324 Entry newClass = null;
1325
1326 for (Instruction i = code.instructionAt(0); i != null; i = i.next()) {
1327
1328 if (verbose > 3) Utils.log.fine(i.toString());
1329
1330 if (i.isNonstandard()
1331 && (!p200.getBoolean(Utils.COM_PREFIX+"invokedynamic")
1332 || i.getBC() != _xxxunusedxxx)) {
1333
1334
1335 String complaint = code.getMethod()
1336 +" contains an unrecognized bytecode "+i
1337 +"; please use the pass-file option on this class.";
1338 Utils.log.warning(complaint);
1339 throw new IOException(complaint);
1340 }
1341
1342 if (i.isWide()) {
1343 if (verbose > 1) {
1344 Utils.log.fine("_wide opcode in "+code);
1345 Utils.log.fine(i.toString());
1346 }
1347 bc_codes.putByte(_wide);
1348 codeHist[_wide]++;
1349 }
1350
1351 int bc = i.getBC();
1352
1353
1354 if (bc == _aload_0) {
1355
1356 Instruction ni = code.instructionAt(i.getNextPC());
1357 if (selfOpVariant(ni) >= 0) {
1358 prevAload = true;
1359 continue;
1360 }
1361 }
1362
1363
1364 int init_bc = initOpVariant(i, newClass);
1365 if (init_bc >= 0) {
1366 if (prevAload) {
1367
1368 bc_codes.putByte(_aload_0);
1369 codeHist[_aload_0]++;
1370 prevAload = false;
1371 }
1372
1373 bc_codes.putByte(init_bc);
1374 codeHist[init_bc]++;
1375 MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1376
1377 int coding = cp.getOverloadingIndex(ref);
1378 bc_initref.putInt(coding);
1379 continue;
1380 }
1381
1382 int self_bc = selfOpVariant(i);
1383 if (self_bc >= 0) {
1384 boolean isField = Instruction.isFieldOp(bc);
1385 boolean isSuper = (self_bc >= _self_linker_op+_self_linker_super_flag);
1386 boolean isAload = prevAload;
1387 prevAload = false;
1388 if (isAload)
1389 self_bc += _self_linker_aload_flag;
1390
1391 bc_codes.putByte(self_bc);
1392 codeHist[self_bc]++;
1393
1394 MemberEntry ref = (MemberEntry) i.getCPRef(curCPMap);
1395 CPRefBand bc_which = selfOpRefBand(self_bc);
1396 Index which_ix = cp.getMemberIndex(ref.tag, ref.classRef);
1397 bc_which.putRef(ref, which_ix);
1398 continue;
1399 }
1400 assert(!prevAload);
1401
1402
1403
1404 codeHist[bc]++;
1405 switch (bc) {
1406 case _tableswitch:
1407 case _lookupswitch:
1408 bc_codes.putByte(bc);
1409 Instruction.Switch isw = (Instruction.Switch) i;
1410
1411 int apc = isw.getAlignedPC();
1412 int npc = isw.getNextPC();
1413
1414 int caseCount = isw.getCaseCount();
1415 bc_case_count.putInt(caseCount);
1416 putLabel(bc_label, code, i.getPC(), isw.getDefaultLabel());
1417 for (int j = 0; j < caseCount; j++) {
1418 putLabel(bc_label, code, i.getPC(), isw.getCaseLabel(j));
1419 }
1420
1421 if (bc == _tableswitch) {
1422 bc_case_value.putInt(isw.getCaseValue(0));
1423 } else {
1424 for (int j = 0; j < caseCount; j++) {
1425 bc_case_value.putInt(isw.getCaseValue(j));
1426 }
1427 }
1428
1429 continue;
1430 }
1431
1432 switch (bc) {
1433 case _xxxunusedxxx:
1434 {
1435 i.setNonstandardLength(3);
1436 int refx = i.getShortAt(1);
1437 Entry ref = (refx == 0)? null: curCPMap[refx];
1438
1439 bc_codes.putByte(_byte_escape);
1440 bc_escsize.putInt(1);
1441 bc_escbyte.putByte(bc);
1442
1443 bc_codes.putByte(_ref_escape);
1444 bc_escrefsize.putInt(2);
1445 bc_escref.putRef(ref);
1446 continue;
1447 }
1448 }
1449
1450 int branch = i.getBranchLabel();
1451 if (branch >= 0) {
1452 bc_codes.putByte(bc);
1453 putLabel(bc_label, code, i.getPC(), branch);
1454 continue;
1455 }
1456 Entry ref = i.getCPRef(curCPMap);
1457 if (ref != null) {
1458 if (bc == _new) newClass = ref;
1459 if (bc == _ldc) ldcHist[ref.tag]++;
1460 CPRefBand bc_which;
1461 int vbc = bc;
1462 switch (i.getCPTag()) {
1463 case CONSTANT_Literal:
1464 switch (ref.tag) {
1465 case CONSTANT_Integer:
1466 bc_which = bc_intref;
1467 switch (bc) {
1468 case _ldc: vbc = _ildc; break;
1469 case _ldc_w: vbc = _ildc_w; break;
1470 default: assert(false);
1471 }
1472 break;
1473 case CONSTANT_Float:
1474 bc_which = bc_floatref;
1475 switch (bc) {
1476 case _ldc: vbc = _fldc; break;
1477 case _ldc_w: vbc = _fldc_w; break;
1478 default: assert(false);
1479 }
1480 break;
1481 case CONSTANT_Long:
1482 bc_which = bc_longref;
1483 assert(bc == _ldc2_w);
1484 vbc = _lldc2_w;
1485 break;
1486 case CONSTANT_Double:
1487 bc_which = bc_doubleref;
1488 assert(bc == _ldc2_w);
1489 vbc = _dldc2_w;
1490 break;
1491 case CONSTANT_String:
1492 bc_which = bc_stringref;
1493 switch (bc) {
1494 case _ldc: vbc = _aldc; break;
1495 case _ldc_w: vbc = _aldc_w; break;
1496 default: assert(false);
1497 }
1498 break;
1499 case CONSTANT_Class:
1500 bc_which = bc_classref;
1501 switch (bc) {
1502 case _ldc: vbc = _cldc; break;
1503 case _ldc_w: vbc = _cldc_w; break;
1504 default: assert(false);
1505 }
1506 break;
1507 default:
1508 bc_which = null;
1509 assert(false);
1510 }
1511 break;
1512 case CONSTANT_Class:
1513
1514 if (ref == curClass.thisClass) ref = null;
1515 bc_which = bc_classref; break;
1516 case CONSTANT_Fieldref:
1517 bc_which = bc_fieldref; break;
1518 case CONSTANT_Methodref:
1519 bc_which = bc_methodref; break;
1520 case CONSTANT_InterfaceMethodref:
1521 bc_which = bc_imethodref; break;
1522 default:
1523 bc_which = null;
1524 assert(false);
1525 }
1526 bc_codes.putByte(vbc);
1527 bc_which.putRef(ref);
1528
1529 if (bc == _multianewarray) {
1530 assert(i.getConstant() == code.getByte(i.getPC()+3));
1531
1532 bc_byte.putByte(0xFF & i.getConstant());
1533 } else if (bc == _invokeinterface) {
1534 assert(i.getLength() == 5);
1535
1536 assert(i.getConstant() == (1+((MemberEntry)ref).descRef.typeRef.computeSize(true)) << 8);
1537 } else {
1538
1539 assert(i.getLength() == ((bc == _ldc)?2:3));
1540 }
1541 continue;
1542 }
1543 int slot = i.getLocalSlot();
1544 if (slot >= 0) {
1545 bc_codes.putByte(bc);
1546 bc_local.putInt(slot);
1547 int con = i.getConstant();
1548 if (bc == _iinc) {
1549 if (!i.isWide()) {
1550 bc_byte.putByte(0xFF & con);
1551 } else {
1552 bc_short.putInt(0xFFFF & con);
1553 }
1554 } else {
1555 assert(con == 0);
1556 }
1557 continue;
1558 }
1559
1560 bc_codes.putByte(bc);
1561 int pc = i.getPC()+1;
1562 int npc = i.getNextPC();
1563 if (pc < npc) {
1564
1565 switch (bc) {
1566 case _sipush:
1567 bc_short.putInt(0xFFFF & i.getConstant());
1568 break;
1569 case _bipush:
1570 bc_byte.putByte(0xFF & i.getConstant());
1571 break;
1572 case _newarray:
1573 bc_byte.putByte(0xFF & i.getConstant());
1574 break;
1575 default:
1576 assert(false);
1577 }
1578 }
1579 }
1580 bc_codes.putByte(_end_marker);
1581 bc_codes.elementCountForDebug++;
1582 codeHist[_end_marker]++;
1583 endCode();
1584 }
1585
1586 int[] codeHist = new int[1<<8];
1587 int[] ldcHist = new int[20];
1588 void printCodeHist() {
1589 assert(verbose > 0);
1590 String[] hist = new String[codeHist.length];
1591 int totalBytes = 0;
1592 for (int bc = 0; bc < codeHist.length; bc++) {
1593 totalBytes += codeHist[bc];
1594 }
1595 for (int bc = 0; bc < codeHist.length; bc++) {
1596 if (codeHist[bc] == 0) { hist[bc] = ""; continue; }
1597 String iname = Instruction.byteName(bc);
1598 String count = "" + codeHist[bc];
1599 count = " ".substring(count.length()) + count;
1600 String pct = "" + (codeHist[bc] * 10000 / totalBytes);
1601 while (pct.length() < 4) {
1602 pct = "0" + pct;
1603 }
1604 pct = pct.substring(0, pct.length()-2) + "." + pct.substring(pct.length()-2);
1605 hist[bc] = count + " " + pct + "% " + iname;
1606 }
1607 Arrays.sort(hist);
1608 System.out.println("Bytecode histogram ["+totalBytes+"]");
1609 for (int i = hist.length; --i >= 0; ) {
1610 if ("".equals(hist[i])) continue;
1611 System.out.println(hist[i]);
1612 }
1613 for (int tag = 0; tag < ldcHist.length; tag++) {
1614 int count = ldcHist[tag];
1615 if (count == 0) continue;
1616 System.out.println("ldc "+ConstantPool.tagName(tag)+" "+count);
1617 }
1618 }
1619 }